package com.aw.baselib.util

import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.content.res.Resources
import android.graphics.Bitmap
import android.graphics.Bitmap.CompressFormat
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Matrix
import android.graphics.Paint
import android.graphics.Paint.Cap
import android.graphics.Paint.Join
import android.graphics.Path
import android.graphics.PixelFormat
import android.graphics.Point
import android.graphics.PointF
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Build
import android.provider.MediaStore
import android.text.TextPaint
import android.text.TextUtils
import android.util.Base64
import android.widget.ImageView
import androidx.core.graphics.drawable.DrawableCompat
import com.aw.baselib.base.AwBaseApplication
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.util.UUID

@SuppressLint("RtlHardcoded")
object AwBitmapUtils {
    private val SUFFIXS: MutableSet<String> = HashSet()

    init {
        SUFFIXS.add("jpg")
        SUFFIXS.add("jpeg")
        SUFFIXS.add("png")
        SUFFIXS.add("bmp")
        SUFFIXS.add("gif")
    }

    /**
     * 将Bitmap转换成Base64字符串
     * @param bitmap
     * @return
     */
    fun bitmapToBase64(bitmap: Bitmap): String? {
        var string: String? = null
        val bStream = ByteArrayOutputStream()
        bitmap.compress(CompressFormat.PNG, 100, bStream)
        val bytes = bStream.toByteArray()
        string = Base64.encodeToString(bytes, Base64.DEFAULT)
        return string
    }

    /**
     * 将Base64字符串转换成Bitmap
     * @param content
     * @return
     */
    fun base64ToBitmp(content: String?): Bitmap? {
        var b: Bitmap? = null
        try {
            val bs = Base64.decode(content, Base64.DEFAULT)
            b = BitmapFactory.decodeByteArray(bs, 0, bs.size)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return b
    }

    // 提取图像Alpha位图
    fun getAlphaBitmap(context: Context, resId: Int): Bitmap {
        val mBitmap = BitmapFactory.decodeResource(context.resources, resId)
        // BitmapDrawable的getIntrinsicWidth（）方法，Bitmap的getWidth（）方法
        // 注意这两个方法的区别
        // Bitmap mAlphaBitmap =
        // Bitmap.createBitmap(mBitmapDrawable.getIntrinsicWidth(),
        // mBitmapDrawable.getIntrinsicHeight(), Config.ARGB_8888);
        val mAlphaBitmap =
            Bitmap.createBitmap(mBitmap.width, mBitmap.height, Bitmap.Config.ARGB_8888)
        val mCanvas = Canvas(mAlphaBitmap)
        val mPaint = Paint()
        mPaint.color = Color.BLUE
        // 从原位图中提取只包含alpha的位图
        val alphaBitmap = mBitmap.extractAlpha()
        // 在画布上（mAlphaBitmap）绘制alpha位图
        mCanvas.drawBitmap(alphaBitmap, 0f, 0f, mPaint)
        return mAlphaBitmap
    }

    /**
     * 旋转图片
     * @param context 当前上下文
     * @param resId 要进行旋转的图片资源ID
     * @param degree 旋转的度数
     * @return
     */
    fun getRotatedBitmap(
        context: Context,
        resId: Int,
        degree: Int
    ): Bitmap? {
        val mBitmap =
            BitmapFactory.decodeResource(context.resources, resId)
        return getRotatedBitmap(mBitmap, degree)
    }

    /**
     * 旋转图片
     * @param mBitmap 要进行旋转的图片
     * @param degree 旋转的度数
     */
    fun getRotatedBitmap(mBitmap: Bitmap, degree: Int): Bitmap? {
        return try {
            val width = mBitmap.width
            val height = mBitmap.height
            val matrix = Matrix()
            matrix.preRotate(degree.toFloat())
            Bitmap.createBitmap(mBitmap, 0, 0, width, height, matrix, true)
        } catch (e: Exception) {
            e.printStackTrace()
            null
        }
    }

    /**
     * 计算图片大小需要调整的比例
     * @param options 操作对象
     * @param reqWidth 需要的宽度
     * @param reqHeight 需要的高度
     * @return
     */
    fun calculateInSampleSize(options: BitmapFactory.Options, reqWidth: Int, reqHeight: Int): Int {
        //图片的原始宽和高
        val width = options.outWidth
        val height = options.outHeight
        var inSampleSize = 1
        if (height > reqHeight || width > reqWidth) {
            //计算目标图片的宽和高与图片原始的宽和高的比例
            val heightRatio = Math.round(height.toFloat() / reqHeight.toFloat())
            val widthRatio = Math.round(width.toFloat() / reqWidth.toFloat())
            //选择比例小的做为调整比例
            inSampleSize = if (heightRatio < widthRatio) heightRatio else widthRatio
        }
        return inSampleSize
    }

    /**
     * 获取资源文件的图片
     * @param res 资源管理对象
     * @param resId 资源ID
     * @param reqWidth 需要的宽度
     * @param reqHeight 需要的高度
     * @return
     */
    fun decodeSampledBitmapFromResource(
        res: Resources?, resId: Int,
        reqWidth: Int, reqHeight: Int
    ): Bitmap {
        // First decode with inJustDecodeBounds=true to check dimensions
        val options = BitmapFactory.Options()
        options.inJustDecodeBounds = true
        BitmapFactory.decodeResource(res, resId, options)

        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight)

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false
        return BitmapFactory.decodeResource(res, resId, options)
    }

    /**
     * 获取指定路径的图片
     * @param path 图片路径
     * @param reqWidth  需要的宽度
     * @param reqHeight  需要的高度
     * @return
     */
    fun decodeSampledBitmapFromFile(path: String?, reqWidth: Int, reqHeight: Int): Bitmap? {
        if (!AwFileUtil.fileExists(path)) {
            return null
        }
        // First decode with inJustDecodeBounds=true to check dimensions
        val options = BitmapFactory.Options()
        options.inJustDecodeBounds = true
        BitmapFactory.decodeFile(path, options)

        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight)

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false
        return BitmapFactory.decodeFile(path, options)
    }

    /**
     * 将Drawable转化成Bitmap
     * @param drawable 待转换的Drawable
     * @return
     */
    fun drawableToBitmap(drawable: Drawable): Bitmap {
        val bitmap = Bitmap.createBitmap(
            drawable.intrinsicWidth,
            drawable.intrinsicHeight,
            if (drawable.opacity != PixelFormat.OPAQUE) Bitmap.Config.ARGB_8888 else Bitmap.Config.RGB_565
        )
        val canvas = Canvas(bitmap)
        drawable.setBounds(0, 0, drawable.intrinsicWidth, drawable.intrinsicHeight)
        drawable.draw(canvas)
        return bitmap
    }

    /** 保存图片到文件 */
    fun saveBitmapToFile(bitmap: Bitmap, path: String?) {
        val file = File(path)
        var out: FileOutputStream? = null
        try {
            out = FileOutputStream(file)
            if (bitmap.compress(CompressFormat.JPEG, 80, out)) {
                out.flush()
                out.close()
            }
        } catch (e: Exception) {
            e.printStackTrace()
        } finally {
            if (out != null) {
                try {
                    out.close()
                } catch (e: IOException) {
                    e.printStackTrace()
                }
            }
        }
    }

    /**
     * 将ImageView控件中的图片保存到文件
     * @param imgView
     * @param path 图片保存路径
     * @return 成功保存为图片文件则返回true，否则返回false
     */
    fun saveToFile(imgView: ImageView, path: String?): Boolean {
        if (imgView.drawable == null) return false
        var bmp: Bitmap? = null
        bmp = try {
            drawableToBitmap(imgView.drawable)
        } catch (e: Exception) {
            return false
        }
        if (bmp == null) return false
        try {
            if (TextUtils.isEmpty(path)) return false else saveBitmapToFile(bmp, path)
        } catch (e: Exception) {
            e.printStackTrace()
            return false
        }
        return true
    }

    /**
     * 绘制指定半径和颜色的实心圆，中心放文字
     * @param radius 半径
     * @param dotColor 圆点颜色
     * @param text 文本内容
     * @param textSize 字体大小
     * @param textColor 字体颜色
     * @return
     */
    fun drawDotWithText(
        radius: Int,
        dotColor: Int,
        text: String?,
        textSize: Float,
        textColor: Int
    ): Bitmap {
        var text = text
        val width = radius * 2
        val dot = Bitmap.createBitmap(width, width, Bitmap.Config.ARGB_8888)
        val c = Canvas(dot)

        // Background Paint
        val p = Paint()
        p.isAntiAlias = true
        p.style = Paint.Style.FILL
        p.color = dotColor
        c.drawCircle(radius.toFloat(), radius.toFloat(), radius.toFloat(), p)

        // TextPaint
        val textPaint = TextPaint()
        textPaint.flags = Paint.ANTI_ALIAS_FLAG
        textPaint.textAlign = Paint.Align.CENTER
        textPaint.isLinearText = true
        textPaint.color = textColor
        textPaint.textSize = textSize

//        int pixel= (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX,
//                textSize, getResources().getDisplayMetrics());
        if (text != null) {
            val length = textPaint.measureText(text) //总长度
            val per = length / text.length //一个字的长度
            val total =
                (Math.sqrt((4 * radius * radius - textSize * textSize).toDouble()) / per).toInt() //总共可以放多少个字
            if (total > 0 && total < text.length) {
                text = text.substring(0, total)
            } else if (total == 0) {
                text = ""
            }
            // x默认是字符的左边在屏幕的位置，如果设置了paint.setTextAlign(Paint.Align.CENTER);
            // 那就是字符的中心，y是指定这个字符baseline在屏幕上的位置。
            // textPaint.descent() + textPaint.ascent() = textHeight;
            c.drawText(
                text,
                radius.toFloat(),
                radius - (textPaint.descent() + textPaint.ascent()) / 2,
                textPaint
            ) //要做5px偏移
        }
        return dot
    }

    /**
     * 绘制指定半径和颜色的实心圆
     * @param radius
     * @param color
     * @return
     */
    fun drawDot(radius: Int, color: Int): Bitmap {
        val dot = Bitmap.createBitmap(radius * 2, radius * 2, Bitmap.Config.ARGB_8888)
        val c = Canvas(dot)
        val p = Paint()
        p.isAntiAlias = true
        p.style = Paint.Style.FILL
        p.color = color
        c.drawCircle(radius.toFloat(), radius.toFloat(), radius.toFloat(), p)
        return dot
    }

    /**
     * 绘制列表条目的下一级标识箭头
     * @param context
     * @return
     */
    fun drawItemNextIndicator(context: Context): Bitmap {
        return drawArrow(
            context, AwDisplayUtil.dip2px(context, 20f), Color.GRAY, ArrowDirection.RIGHT
        )
    }

    /**
     * 绘制的箭头
     * @param context
     * @param sideLen 边长，左、右方向时指箭头高度，上、下方向时指箭头宽度
     * @param color
     * @param direct
     * @return
     */
    fun drawArrow(
        context: Context,
        sideLen: Int,
        color: Int,
        direct: ArrowDirection
    ): Bitmap {
        val lineWidth = AwDisplayUtil.dip2px(context, 2f)
        //规划箭头路径
        val offsetWidth = sideLen / 4
        val end1 =
            Point(offsetWidth + lineWidth, lineWidth)
        val end2 =
            Point(offsetWidth + lineWidth, sideLen - lineWidth)
        val header =
            Point(offsetWidth + sideLen / 2, sideLen / 2)
        val arrowPath = Path()
        arrowPath.reset()
        arrowPath.moveTo(end1.x.toFloat(), end1.y.toFloat())
        arrowPath.lineTo(header.x.toFloat(), header.y.toFloat())
        arrowPath.lineTo(end2.x.toFloat(), end2.y.toFloat())
        val arrow = Bitmap.createBitmap(
            sideLen,
            sideLen,
            Bitmap.Config.ARGB_8888
        )
        val c = Canvas(arrow)
        val p = Paint()
        p.isAntiAlias = true
        p.style = Paint.Style.STROKE
        p.strokeWidth = lineWidth.toFloat()
        p.color = color
        c.drawPath(arrowPath, p)
        return if (direct.degree == 0) arrow else getRotatedBitmap(arrow, direct.degree)!!
    }

    fun drawCrossIcon(context: Context, sideLen: Int, color: Int): Bitmap {
        return drawCrossIcon(context, sideLen, -1, color)
    }

    fun drawDeclineIcon(context: Context, sideLen: Int, color: Int): Bitmap {
        return drawDeclineIcon(context, sideLen, -1, color)
    }

    fun drawDirectLeftTriangle(context: Context, size: Int, color: Int, solid: Boolean): Bitmap {
        return drawTriangle(context, size, color, solid, ArrowDirection.LEFT)
    }

    fun drawTriangle(
        context: Context,
        size: Int,
        color: Int,
        solid: Boolean,
        direct: ArrowDirection
    ): Bitmap {
        val fSize = (size.toString() + "").toFloat()
        val p1 = PointF(0f, 0f)
        val p2 = PointF(fSize / 2, fSize / 2)
        val p3 = PointF(0f, fSize)
        val arrowPath = Path()
        arrowPath.reset()
        arrowPath.moveTo(p1.x, p1.y)
        arrowPath.lineTo(p2.x, p2.y)
        arrowPath.lineTo(p3.x, p3.y)
        val arrow = Bitmap.createBitmap(
            size,
            size,
            Bitmap.Config.ARGB_8888
        )
        val c = Canvas(arrow)
        val p = Paint()
        p.isAntiAlias = true
        if (!solid) {
            val lineWidth = AwDisplayUtil.dip2px(context, 2f)
            p.style = Paint.Style.STROKE
            p.strokeWidth = lineWidth.toFloat()
        } else {
            p.style = Paint.Style.FILL
        }
        p.color = color
        c.drawPath(arrowPath, p)
        return if (direct.degree == 0) arrow else getRotatedBitmap(arrow, direct.degree)!!
    }

    /**
     * 绘制十字图标
     * @param context
     * @param sideLen 图标边长
     * @param lineWidth (单位：dp)
     * @param color 十字线的颜色
     * @return
     */
    fun drawCrossIcon(context: Context, sideLen: Int, lineWidth: Int, color: Int): Bitmap {
        val lp = Point(0, sideLen / 2)
        val rp = Point(sideLen, sideLen / 2)
        val tp = Point(sideLen / 2, 0)
        val bp = Point(sideLen / 2, sideLen)
        val path = Path()
        path.moveTo(lp.x.toFloat(), lp.y.toFloat())
        path.lineTo(rp.x.toFloat(), rp.y.toFloat())
        path.moveTo(tp.x.toFloat(), tp.y.toFloat())
        path.lineTo(bp.x.toFloat(), bp.y.toFloat())
        val cross = Bitmap.createBitmap(sideLen, sideLen, Bitmap.Config.ARGB_8888)
        val c = Canvas(cross)
        val lineWidthInDp =
            AwDisplayUtil.dip2px(context, (if (lineWidth == -1) 2 else lineWidth).toFloat())
        val paint = createLinePaint(lineWidthInDp, color)
        c.drawPath(path, paint)
        return cross
    }

    /**
     * 绘制十字图标
     * @param context
     * @param sideLen 图标边长
     * @param lineWidth (单位：dp)
     * @param color 十字线的颜色
     * @return
     */
    fun drawDeclineIcon(context: Context, sideLen: Int, lineWidth: Int, color: Int): Bitmap {
        val lp = Point(0, sideLen / 2)
        val rp = Point(sideLen, sideLen / 2)
        val path = Path()
        path.moveTo(lp.x.toFloat(), lp.y.toFloat())
        path.lineTo(rp.x.toFloat(), rp.y.toFloat())
        val cross = Bitmap.createBitmap(sideLen, sideLen, Bitmap.Config.ARGB_8888)
        val c = Canvas(cross)
        val lineWidthInDp =
            AwDisplayUtil.dip2px(context, (if (lineWidth == -1) 2 else lineWidth).toFloat())
        val paint = createLinePaint(lineWidthInDp, color)
        c.drawPath(path, paint)
        return cross
    }

    private fun createLinePaint(lineWidth: Int, color: Int): Paint {
        val p = Paint()
        p.isAntiAlias = true
        p.style = Paint.Style.STROKE
        p.strokeWidth = lineWidth.toFloat()
        p.color = color
        p.strokeCap = Cap.ROUND
        p.strokeJoin = Join.BEVEL
        return p
    }

    /**
     * 将bitmap中的某种颜色值替换成新的颜色
     * @param oldBitmap
     * @param oldColor
     * @param newColor
     * @return
     */
    fun replaceBitmapColor(oldBitmap: Bitmap, oldColor: Int, newColor: Int): Bitmap {
        val mBitmap = oldBitmap.copy(Bitmap.Config.ARGB_8888, true)
        //循环获得bitmap所有像素点
        val mBitmapWidth = mBitmap.width
        val mBitmapHeight = mBitmap.height
        val mArrayColorLengh = mBitmapWidth * mBitmapHeight
        for (i in 0 until mBitmapHeight) {
            for (j in 0 until mBitmapWidth) {
                //获得Bitmap 图片中每一个点的color颜色值
                //将需要填充的颜色值如果不是
                //在这说明一下 如果color 是全透明 或者全黑 返回值为 0
                //getPixel()不带透明通道 getPixel32()才带透明部分 所以全透明是0x00000000
                //而不透明黑色是0xFF000000 如果不计算透明部分就都是0了
                val color = mBitmap.getPixel(j, i)
                //将颜色值存在一个数组中 方便后面修改
                if (color == oldColor) {
                    mBitmap.setPixel(j, i, newColor) //将白色替换成透明色
                }
            }
        }
        return mBitmap
    }

    fun bitmap2Bytes(bitmap: Bitmap): ByteArray {
        val baos = ByteArrayOutputStream()
        bitmap.compress(CompressFormat.JPEG, 100, baos)
        return baos.toByteArray()
    }

    fun Bytes2bitmap(bytes: ByteArray): Bitmap {
        return BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
    }

    /**
     * 保存base64图片到相册
     * @param base64Str
     * @param path
     * @param insertAlbum             是否直接插入android系统图库
     */
    fun base64ToImgFile(
        mContext: Context,
        base64Str: String?,
        path: String?,
        insertAlbum: Boolean
    ): String? {
        var path = path
        try {
            val bt = base64ToBitmp(base64Str)
            if (bt != null) {
                if (insertAlbum) {
                    //把文件插入到系统图库
                    path = MediaStore.Images.Media.insertImage(
                        mContext.contentResolver,
                        bt,
                        UUID.randomUUID().toString() + ".png",
                        "description"
                    )
                } else {
                    saveBitmapToFile(bt, path)
                    //保存图片后发送广播通知更新数据库
                    val file = File(path)
                    val uri = Uri.fromFile(file)
                    mContext.sendBroadcast(Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri))
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return path
    }

    /**
     * 矢量图转Bitmap
     *
     * @param drawableId 矢量图ID
     * @return
     */
    fun getBitmapFromVectorDrawable(drawableId: Int): Bitmap {
        var drawable = AwBaseApplication.instance?.getDrawable(drawableId)
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            drawable = DrawableCompat.wrap(drawable!!).mutate()
        }
        val bitmap = Bitmap.createBitmap(
            drawable!!.intrinsicWidth, drawable.intrinsicHeight,
            Bitmap.Config.ARGB_8888
        )
        val canvas = Canvas(bitmap)
        drawable.setBounds(0, 0, canvas.width, canvas.height)
        drawable.draw(canvas)
        return bitmap
    }

    /**
     * 矢量图转Bitmap
     *
     * @param context
     * @param drawable 矢量图Drawable
     * @return
     */
	@JvmStatic
	fun getBitmapFromVectorDrawable(context: Context?, drawable: Drawable): Bitmap {
        var drawable = drawable
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            drawable = DrawableCompat.wrap(drawable).mutate()
        }
        val bitmap = Bitmap.createBitmap(
            drawable.intrinsicWidth, drawable.intrinsicHeight,
            Bitmap.Config.ARGB_8888
        )
        val canvas = Canvas(bitmap)
        drawable.setBounds(0, 0, canvas.width, canvas.height)
        drawable.draw(canvas)
        return bitmap
    }

    enum class ArrowDirection(var degree: Int) {
        LEFT(180), RIGHT(0), TOP(270), BOTTOM(90)

    }
}